package com.artfii.fluentsql.core.jdbc;

import com.artfii.fluentsql.core.tools.DbUitls;
import com.artfii.fluentsql.core.tools.PropUtil;
import com.zaxxer.hikari.HikariConfig;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * FluentSqlConfig 配置项
 */
public class FluentSqlConfig {
    public static FluentSqlConfig default_config;

    private final String def_file_name = "fluentsql-";
    private String default_env = "dev";

    //////////////////////////////////////// 配置文件(YML)对应的属性 /////////////////////////////////////////
    private List<DataSourceConfig> datasources; //数据源
    private CP connect_pool; //数据连接池的配置
    private Boolean sql_hack_check = false; //是否检查SQL注入
    private Boolean read_write_diff_way = false ; //是否读写分离
    ///////////////////////////////////////////////////////////////////////////////////////

    private HashMap<Number, DataSource> dataSourceMap = new HashMap<>(); //所有的数据源配置项MAP
    private DataSource masterDs = null; //主库
    private List<DataSource> slaveList = new ArrayList<>(); //从库

    public FluentSqlConfig() {
        default_config = this;
    }

    public FluentSqlConfig build(String env) {
        env = env == null ? default_env : env;
        String ymlFile = "" + def_file_name + env + ".yml";
        default_config = PropUtil.loadYmlToClass(ymlFile, FluentSqlConfig.class);
        buildDataSource(default_config);
        return default_config;
    }

    private FluentSqlConfig buildDataSource(FluentSqlConfig config) {
        for (DataSourceConfig dsc : config.datasources) {
            DataSource ds = DbUitls.getHikariDataSource(buildHikariConfig(dsc,config.connect_pool));
            if (dsc.isMaster()) {
                config.masterDs = ds;
            } else {
                config.slaveList.add(ds);
            }
            config.dataSourceMap.put(dsc.getId(), ds);
        }
        return config;
    }

    private HikariConfig buildHikariConfig(DataSourceConfig dsc,CP cp) {
        HikariConfig hConf = new HikariConfig();
        hConf.setJdbcUrl(dsc.getUrl());
        hConf.setDriverClassName(dsc.getDriver_class_name());
        hConf.setUsername(dsc.getUsername());
        hConf.setPassword(dsc.getPassword());
        if (null != cp.getPool_maximum_size() && cp.getPool_maximum_size() > 0) {
            hConf.setMaximumPoolSize(cp.getPool_maximum_size());
        }
        if (null != cp.getPool_minimum_idle() && cp.getPool_minimum_idle() > 0) {
            hConf.setMinimumIdle(cp.getPool_minimum_idle());
        }
        if (null != cp.getConn_max_Life_time() && cp.getConn_max_Life_time() > 0) {
            hConf.setMaxLifetime(cp.getConn_max_Life_time());
        }
        hConf.setConnectionInitSql("SELECT 1");
        return hConf;
    }

    public List<DataSourceConfig> getSlaveConfigList() {
        return datasources.stream().filter(d -> d.isMaster() == false).collect(Collectors.toList());
    }

    public HashMap<Number, DataSource> getDataSourceMap() {
        return dataSourceMap;
    }

    public DataSource getMasterDs() {
        return masterDs;
    }

    public List<DataSource> getSlaveList() {
        return slaveList;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////


    public List<DataSourceConfig> getDatasources() {
        return datasources;
    }

    public void setDatasources(List<DataSourceConfig> datasources) {
        this.datasources = datasources;
    }

    public Boolean getSql_hack_check() {
        if(sql_hack_check == null){
            return false;
        }
        return sql_hack_check;
    }

    public void setSql_hack_check(Boolean sql_hack_check) {
        this.sql_hack_check = sql_hack_check;
    }

    public Boolean getRead_write_diff_way() {
        if (null == read_write_diff_way) {
            return false;
        }
        return read_write_diff_way;
    }

    public void setRead_write_diff_way(Boolean read_write_diff_way) {
        this.read_write_diff_way = read_write_diff_way;
    }

    public CP getConnect_pool() {
        return connect_pool;
    }

    public void setConnect_pool(CP connect_pool) {
        this.connect_pool = connect_pool;
    }

    public void setDataSourceMap(HashMap<Number, DataSource> dataSourceMap) {
        this.dataSourceMap = dataSourceMap;
    }

    public void setMasterDs(DataSource masterDs) {
        this.masterDs = masterDs;
    }

    public void setSlaveList(List<DataSource> slaveList) {
        this.slaveList = slaveList;
    }

    @Override
    public String toString() {
        return "FluentSqlConfig{" +
                "def_file_name='" + def_file_name + '\'' +
                ", default_env='" + default_env + '\'' +
                ", datasources=" + datasources +
                ", connect_pool=" + connect_pool +
                ", sql_hack_check=" + sql_hack_check +
                ", read_write_diff_way=" + read_write_diff_way +
                ", dataSourceMap=" + dataSourceMap +
                ", masterDs=" + masterDs +
                ", slaveList=" + slaveList +
                '}';
    }

    ////////////////////////////////////////// INNER CLASS /////////////////////////////////////////////
    /**
     * 数据源配置的包装
     */
    public static class DataSourceConfig {
        private Integer id;
        /**
         * 主库还是从库
         */
        private Boolean master;
        private String driver_class_name;
        private String url;
        private String username;
        private String password;
        /**
         * 权重比例(1-100)
         */
        private Integer weight_rate;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public Boolean isMaster() {
            if (null == master) { // 没有配置master属性则默认为主库
                return true;
            }
            return master;
        }

        public void setMaster(Boolean master) {
            this.master = master;
        }

        public String getDriver_class_name() {
            return driver_class_name;
        }

        public void setDriver_class_name(String driver_class_name) {
            this.driver_class_name = driver_class_name;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public Integer getWeight_rate() {
            return weight_rate;
        }

        public void setWeight_rate(Integer weight_rate) {
            this.weight_rate = weight_rate;
        }

        @Override
        public String toString() {
            return "DataSourceConfig{" +
                    "id=" + id +
                    ", master=" + master +
                    ", driver_class_name='" + driver_class_name + '\'' +
                    ", url='" + url + '\'' +
                    ", weight_rate=" + weight_rate +
                    '}';
        }
    }

    public static class CP {
        private String pool_driver;
        private String pool_name;
        private Integer pool_minimum_idle;  //最小连接数
        private Integer pool_maximum_size;  //最大连接数
        private Integer conn_max_Life_time; //连接最大存活时间

        public String getPool_driver() {
            return pool_driver;
        }

        public void setPool_driver(String pool_driver) {
            this.pool_driver = pool_driver;
        }

        public String getPool_name() {
            return pool_name;
        }

        public void setPool_name(String pool_name) {
            this.pool_name = pool_name;
        }

        public Integer getPool_minimum_idle() {
            return pool_minimum_idle;
        }

        public void setPool_minimum_idle(Integer pool_minimum_idle) {
            this.pool_minimum_idle = pool_minimum_idle;
        }

        public Integer getPool_maximum_size() {
            return pool_maximum_size;
        }

        public void setPool_maximum_size(Integer pool_maximum_size) {
            this.pool_maximum_size = pool_maximum_size;
        }

        public Integer getConn_max_Life_time() {
            return conn_max_Life_time;
        }

        public void setConn_max_Life_time(Integer conn_max_Life_time) {
            this.conn_max_Life_time = conn_max_Life_time;
        }

        @Override
        public String toString() {
            final StringBuffer sb = new StringBuffer("CP{");
            sb.append("pool_driver='").append(pool_driver).append('\'');
            sb.append(", pool_name='").append(pool_name).append('\'');
            sb.append(", pool_minimum_idle=").append(pool_minimum_idle);
            sb.append(", pool_maximum_size=").append(pool_maximum_size);
            sb.append(", conn_max_Life_time=").append(conn_max_Life_time);
            sb.append('}');
            return sb.toString();
        }
    }

}